//-------------------------------------------------------------------
//	Copyright (c) 2013  Zhirnov Andrey
//	This file is part of the "Noise Library" project.
//	See copyright notice in "linNoiseCL.h".
//-------------------------------------------------------------------

#include "CContext.h"

namespace Noise
{
	inline Program		ProgramCast (CProgramPtr prog)	{ return (Program) prog.ptr(); }
	inline CProgramPtr	CProgramCast (Program prog)		{ return CProgramPtr( (CProgram *)prog ); }

	inline Source	SourceCast (CSourcePtr src)		{ return (Source) src.ptr(); }
	inline CSourcePtr	CSourceCast (Source src)	{ return CSourcePtr( (CSource *)src ); }

	
// CONTEXT

	// nCreateContext
	NOISE_ENTRY EResult NOISE_CALL nCreateContext (EContextFlags flags)
	{
		EResult res = CONTEXT()->Create( flags );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nCreateContextFromCL
	NOISE_ENTRY EResult NOISE_CALL nCreateContextFromCL (cl_platform_id platformId, cl_device_id deviceId, cl_context context)
	{
		EResult res = CONTEXT()->CreateCL( platformId, deviceId, context );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nCreateContextFromGL
	NOISE_ENTRY EResult NOISE_CALL nCreateContextFromGL (void *dc, void *rc, EContextFlags flags)
	{
		EResult res = CONTEXT()->CreateGL( dc, rc, flags );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nShareContextDX
	NOISE_ENTRY EResult NOISE_CALL nShareContextDX (void *dx, EContextFlags flags)
	{
		EResult res = CONTEXT()->CreateDX( dx, flags );
		CHECK_WARNING( res == OK );
		return res;
	}
	
	// nDeleteContext
	NOISE_ENTRY void NOISE_CALL nDeleteContext ()
	{
		return CONTEXT()->Delete();
	}
	
	// nSetContextInteger
	NOISE_ENTRY EResult NOISE_CALL nSetContextInteger (EContextParameter pname, const int *v, int count)
	{
		EResult res = CONTEXT()->SetInteger( pname, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetContextInteger
	NOISE_ENTRY EResult NOISE_CALL nGetContextInteger (EContextQuery pname, int *v, int count)
	{
		EResult res = CONTEXT()->GetInteger( pname, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}


// PROGRAM

	// nCreateProgram
	NOISE_ENTRY Program NOISE_CALL nCreateProgram (EProgram type)
	{
		Program res = ProgramCast( CONTEXT()->CreateProgram( type ) );
		CHECK_WARNING( res != null );
		return res;
	}

	// nDeleteProgram
	NOISE_ENTRY void NOISE_CALL nDeleteProgram (Program prog)
	{
		CHECK_ARGUMENT_R( prog != null, );
		return CONTEXT()->DeleteProgram( CProgramCast( prog ) );
	}

	// nBuildProgram
	NOISE_ENTRY EResult NOISE_CALL nBuildProgram (Program prog, Source src, EBuildOptions options)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		EResult res = CProgramCast( prog )->Build( CSourceCast( src ), options );
		CHECK_WARNING( res == OK );
		return res;
	}
	
	// nSetProgramInteger
	NOISE_ENTRY EResult NOISE_CALL nSetProgramInteger (Program prog, EProgramParameter pname, const int *v, int count)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->SetInteger( pname, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}
	
	// nSetProgramFloat
	NOISE_ENTRY EResult NOISE_CALL nSetProgramFloat (Program prog, EProgramParameter pname, const float *v, int count)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );

		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect;
			vect.ConvertFrom( uni_array<const float>( v, count ) );

			res = CProgramCast( prog )->SetReal( pname, vect.ptr(), vect.Count() );
		}
		else
			res = CProgramCast( prog )->SetReal( pname, (const real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nSetProgramDouble
	NOISE_ENTRY EResult NOISE_CALL nSetProgramDouble (Program prog, EProgramParameter pname, const double *v, int count)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );

		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect;
			vect.ConvertFrom( uni_array<const double>( v, count ) );

			res = CProgramCast( prog )->SetReal( pname, vect.ptr(), vect.Count() );
		}
		else
			res = CProgramCast( prog )->SetReal( pname, (const real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetProgramInteger
	NOISE_ENTRY EResult NOISE_CALL nGetProgramInteger (Program prog, EProgramQuery pname, int *v, int count)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->GetInteger( pname, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetProgramFloat
	NOISE_ENTRY EResult NOISE_CALL nGetProgramFloat (Program prog, EProgramQuery pname, float *v, int count)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		
		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect;
			vect.Resize( count, false );

			CProgramCast( prog )->GetReal( pname, vect.ptr(), vect.Count() );

			FOR( i, vect ) {
				v[0] = float( vect[0] );
			}
		}
		else
			res = CProgramCast( prog )->GetReal( pname, (real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetProgramDouble
	NOISE_ENTRY EResult NOISE_CALL nGetProgramDouble (Program prog, EProgramQuery pname, double *v, int count)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );

		EResult res;
		
		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect;
			vect.Resize( count, false );

			res = CProgramCast( prog )->GetReal( pname, vect.ptr(), vect.Count() );

			FOR( i, vect ) {
				v[0] = double( vect[0] );
			}
		}
		else
			res = CProgramCast( prog )->GetReal( pname, (real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetProgramString
	NOISE_ENTRY EResult NOISE_CALL nGetProgramString (Program prog, EProgramQuery pname, char *buf, int length)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->GetString( pname, buf, length );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nRenderToMemory
	NOISE_ENTRY EResult NOISE_CALL nRenderToMemory (Program prog,
													int width, int height, int depth, 
													int rowSize, int sliceSize,
													EPixelFormat format, EPixelType type, void *pixels)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->RenderToMemory( uvec3( Max<uint>(width, 1), Max<uint>(height, 1), Max<uint>(depth, 1) ),
															uvec2( rowSize, sliceSize ), format, type, pixels );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nRenderToImage
	NOISE_ENTRY EResult NOISE_CALL nRenderToImage (Program prog,
												   int width, int height, int depth,
												   EPixelFormat format, EPixelType type,
												   EImageType imageType, const char *filename)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->RenderToImage( uvec3( Max<uint>(width, 1), Max<uint>(height, 1), Max<uint>(depth, 1) ),
															format, type, imageType, filename );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nRenderToImage
	NOISE_ENTRY EResult NOISE_CALL nRenderToImageCL (Program prog, cl_mem imageId)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->RenderToImageCL( imageId );
		CHECK_WARNING( res == OK );
		return res;
	}
	
	// nRenderToSubImageCL
	NOISE_ENTRY EResult NOISE_CALL nRenderToSubImageCL (Program prog, cl_mem imageId,
														int xoffset, int yoffset, int zoffset,
														int width, int height, int depth)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->RenderToSubImageCL( imageId, svec3(xoffset, yoffset, zoffset), svec3(width, height, depth) );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nRenderToTextureGL
	NOISE_ENTRY EResult NOISE_CALL nRenderToTextureGL (Program prog, GLenum target, GLuint id, int level)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->RenderToTextureGL( target, id, level );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nRenderToTextureDX
	NOISE_ENTRY EResult NOISE_CALL nRenderToTextureDX (Program prog, void *dxTex)
	{
		CHECK_ARGUMENT_R( prog != null, INVALID_PROGRAM );
		EResult res = CProgramCast( prog )->RenderToTextureDX( dxTex );
		CHECK_WARNING( res == OK );
		return res;
	}
	

// SOURCE

	// nCreateSource
	NOISE_ENTRY Source NOISE_CALL nCreateSource (ESource type)
	{
		Source res = SourceCast( CONTEXT()->CreateSource( type ) );
		CHECK_WARNING( res != null );
		return res;
	}
	
	NOISE_ENTRY Source NOISE_CALL nCreateSourceCopy (Source src)
	{
		Source res = SourceCast( CONTEXT()->CreateSourceCopy( CSourceCast( src ) ) );
		CHECK_WARNING( res != null );
		return res;
	}

	// nDeleteSource
	NOISE_ENTRY void NOISE_CALL nDeleteSource (Source src)
	{
		CHECK_ARGUMENT_R( src != null, );
		return CONTEXT()->DeleteSource( CSourceCast( src ) );
	}
	
	// nGetSourceInteger
	NOISE_ENTRY EResult NOISE_CALL nGetSourceInteger (Source src, ESourceQuery pname, int *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		EResult res = CSourceCast( src )->GetInteger( pname, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nSetArgSource
	NOISE_ENTRY EResult NOISE_CALL nSetArgSource (Source src, EArgument type, Source inputSource)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		EResult res = CSourceCast( src )->SetArg( type, CSourceCast( inputSource ) );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nSetArgDouble
	NOISE_ENTRY EResult NOISE_CALL nSetArgDouble (Source src, EArgument type, const double *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );

		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect;
			vect.ConvertFrom( uni_array<const double>( v, count ) );

			res = CSourceCast( src )->SetArg( type, vect.ptr(), vect.Count() );
		}
		else
			res = CSourceCast( src )->SetArg( type, (const real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nSetArgFloat
	NOISE_ENTRY EResult NOISE_CALL nSetArgFloat (Source src, EArgument type, const float *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		
		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect;
			vect.ConvertFrom( uni_array<const float>( v, count ) );

			res = CSourceCast( src )->SetArg( type, vect.ptr(), vect.Count() );
		}
		else
			res = CSourceCast( src )->SetArg( type, (const real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}
	
	// nSetArgInteger
	NOISE_ENTRY EResult NOISE_CALL nSetArgInteger (Source src, EArgument type, const int *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		EResult res = CSourceCast( src )->SetArg( type, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}
	
	// nGetArgSource
	NOISE_ENTRY EResult NOISE_CALL nGetArgSource (Source src, EArgument type, Source *inputSource)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		CSourcePtr	source;
		EResult		res = CSourceCast( src )->GetArg( type, source );
		*inputSource = SourceCast( source );
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetArgDouble
	NOISE_ENTRY EResult NOISE_CALL nGetArgDouble (Source src, EArgument type, double *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );

		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect( count );

			res = CSourceCast( src )->GetArg( type, vect.ptr(), vect.Count() );
			FOR( i, vect )	{ v[i] = vect[i]; }
		}
		else
			res = CSourceCast( src )->GetArg( type, (real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetArgFloat
	NOISE_ENTRY EResult NOISE_CALL nGetArgFloat (Source src, EArgument type, float *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );

		EResult res;

		if ( sizeof(real) != sizeof(v[0]) )
		{
			pod_array<real>	vect( count );

			res = CSourceCast( src )->GetArg( type, vect.ptr(), vect.Count() );
			FOR( i, vect )	{ v[i] = vect[i]; }
		}
		else
			res = CSourceCast( src )->GetArg( type, (real *)v, count );
		
		CHECK_WARNING( res == OK );
		return res;
	}

	// nGetArgInteger
	NOISE_ENTRY EResult NOISE_CALL nGetArgInteger (Source src, EArgument type, int *v, int count)
	{
		CHECK_ARGUMENT_R( src != null, INVALID_SOURCE );
		EResult res = CSourceCast( src )->GetArg( type, v, count );
		CHECK_WARNING( res == OK );
		return res;
	}


}	// Noise

#if !defined(_NOISE_NO_LOG)
#	include <logger/ux_logger_lib.h>
#endif
